package lx.exalarm.alarm;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import lx.exalarm.utils.StringUtils;
import lx.exalarm.utils.log.Log;

/**
 * Created by liuxu on 15-2-27.
 */
public class AlarmBean implements Serializable {

    public static final int WEEK_SUNDAY = 0;
    public static final int WEEK_MONDAY = 1;
    public static final int WEEK_TUESDAY = 2;
    public static final int WEEK_WEDNESDAY = 3;
    public static final int WEEK_THURSDAY = 4;
    public static final int WEEK_FRIDAY = 5;
    public static final int WEEK_SATURDAY = 6;

    private int id;  // id from database primary key
    private int hour;  // hour for alarm
    private int minute;  // minute for alarm
    private int repeat;  // repeat weekdays, use bit to represent each weekday
    private boolean enabled;  // if the alarm is enabled
    private int firstActionId;  // first action id in the list
    private transient List<ActionBean> actions;  // actions
    private transient boolean[] repeatDays;  // repeat days get from "repeat" field

    public void setId(int id) {
        this.id = id;
    }

    public int getId() {
        return this.id;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public boolean isEnabled() {
        return this.enabled;
    }

    public void setHour(int hour) {
        this.hour = hour;
    }

    public int getHour() {
        return this.hour;
    }

    public void setMinute(int minute) {
        this.minute = minute;
    }

    public int getMinute() {
        return this.minute;
    }

    public void setRepeat(int repeat) {
        this.repeat = repeat;
        initRepeatDays();
    }

    public int getRepeat() {
        return this.repeat;
    }

    public void setFirstActionId(int firstActionId) {
        this.firstActionId = firstActionId;
    }

    public int getFirstActionId() {
        return this.firstActionId;
    }

    public void setActions(List<ActionBean> actions) {
        this.actions = actions;
    }

    public List<ActionBean> getActions() {
        return this.actions;
    }

    /**
     * get alarm hour and minute as string in form of "xx:xx"
      * @return time string
     */
    public String getTimeTitle() {
        return getFormatedTime(this.hour) + ":" + getFormatedTime(this.minute);
    }

    /**
     * get first enabled action in the list.
     * @return action
     */
    public ActionBean getFirstEnabledAction() {
        ActionBean firstEnabledAction = null;
        for (ActionBean action : this.actions) {
            if (action.isEnabled()) {
                firstEnabledAction = action;
                break;
            }
        }
        return firstEnabledAction;
    }

    /**
     * get start time for this alarm, in millisecond, since January 1, 1970 00:00:00.0 UTC.
     * @return millisecond
     */
    public long getStartTime() {
        long currentTime = System.currentTimeMillis();

        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(currentTime);
        Log.d("AlarmBean.getStartTime, cur=" + c);
        int curH = c.get(Calendar.HOUR_OF_DAY);
        int curM = c.get(Calendar.MINUTE);

        // if the time has passed, roll to the next day
        if (curH > getHour() || (curH == getHour() && curM >= getMinute())) {
            c.roll(Calendar.DAY_OF_YEAR, 1);
        }

        // find the first enabled day
        while (!isDayRepeat(c.get(Calendar.DAY_OF_WEEK) - 1)) {
            c.roll(Calendar.DAY_OF_YEAR, 1);
        }

        c.set(Calendar.HOUR_OF_DAY, getHour());
        c.set(Calendar.MINUTE, getMinute());
        c.set(Calendar.SECOND, 59);
        c.set(Calendar.MILLISECOND, 999);

        Log.d("AlarmBean.getStartTime, ret=" + c);
        return c.getTimeInMillis();
    }

    public boolean[] getRepeatDays() {
        return this.repeatDays;
    }

    /**
     * check if a weekday needs the alarm.
     * @param field the weekday code, from 0-6, or use WEEK_SUNDAY - WEEK_SATURDAY
     * @return true if a weekday needs the alarm
     */
    public boolean isDayRepeat(int field) {
        if (field < 0 || field >= 7) {
            throw new IllegalArgumentException("field out of range, should be [0, 6]");
        }
        if (repeatDays == null) {
            initRepeatDays();
        }
        return repeatDays[field];
    }

    /**
     * set if a weekday needs the alarm.
     * @param field the weekday code, from 0-6, or use WEEK_SUNDAY - WEEK_SATURDAY
     * @param enabled if a weekday needs the alarm
     */
    public void setDayRepeat(int field, boolean enabled) {
        if (field < 0 || field >= 7) {
            throw new IllegalArgumentException("field out of range, should be [0, 6]");
        }
        if (repeatDays == null) {
            initRepeatDays();
        }
        repeatDays[field] = enabled;
        if (enabled) {
            repeat |= (0x01 << field);
        } else {
            repeat &= ~(0x01 << field);
        }
    }

    private void initRepeatDays() {
        repeatDays = new boolean[7];
        for (int i = 0; i < repeatDays.length; i ++) {
            repeatDays[i] = ((repeat & (0x01 << i)) != 0);
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder().append(this.getClass().getSimpleName())
                .append("-id=").append(getId())
                .append(",hour=").append(getHour())
                .append(",minute=").append(getMinute())
                .append(",repeat=").append(getRepeat())
                .append(",enabled=").append(isEnabled())
                .append(",actions:\n");
        List<ActionBean> actions = getActions();
        if (actions == null || actions.size() == 0) {
            sb.append("\t NONE\n");
        } else {
            for (ActionBean action : actions) {
                sb.append("\t ").append(action.toString()).append("\n");
            }
        }
        return sb.toString();
    }

    private static String getFormatedTime(int time) {
        String tmpStr = String.valueOf(time);
        if (time < 10) {
            tmpStr = "0" + tmpStr;
        }
        return tmpStr;
    }

    public static AlarmBean createDefaultAlarm() {
        AlarmBean alarm = new AlarmBean();
        String hourStr = StringUtils.getCurrentTimeString("HH");
        String minuteStr = StringUtils.getCurrentTimeString("mm");
        int hour = Integer.parseInt(hourStr);
        int minute = Integer.parseInt(minuteStr);
        alarm.setId(-1);
        alarm.setHour(hour);
        alarm.setMinute(minute - minute % 5);
        alarm.setRepeat(0x3e);
        alarm.setEnabled(false);

        ActionBean actionAudio1 = ActionBean.createDefaultAudioAction();
        ActionBean actionAudio2 = ActionBean.createDefaultAudioAction();
        ActionBean actionVideo1 = ActionBean.createDefaultVideoAction();
        actionAudio1.setInterval(0);
        actionAudio2.setInterval(0);
        actionVideo1.setInterval(0);

        ArrayList<ActionBean> actions = new ArrayList<>(3);
        actions.add(actionAudio1);
        actions.add(actionAudio2);
        actions.add(actionVideo1);
        alarm.setActions(actions);
        return alarm;
    }
}
